﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Windows.Foundation;
using Windows.UI.Xaml.Data;

namespace douban.Core.ViewModels
{
    /// <summary>
    /// 增量加载
    /// </summary>
    public class IncrementalLoadingCollection<T>:ObservableCollection<T>, ISupportIncrementalLoading
    {
        private int _start = 0;
        // 这里为了简单使用了Tuple<IList<T>, bool>作为返回值，第一项是新项目集合，第二项是否还有更多，也可以自定义实体类
        Func<int,int, Task<Tuple<IEnumerable<T>, bool>>> _dataFetchDelegate = null;

        public IncrementalLoadingCollection(Func<int,int, Task<Tuple<IEnumerable<T>, bool>>> dataFetchDelegate)
        {
            if (dataFetchDelegate == null) throw new ArgumentNullException("dataFetchDelegate");

            _dataFetchDelegate = dataFetchDelegate;
        }


        /// <summary>
        /// 初始化从视图的增量加载。
        /// </summary>
        /// <returns>
        /// 加载操作的换行结果。
        /// </returns>
        /// <param name="count">要加载的项的数目。</param>
        public IAsyncOperation<LoadMoreItemsResult> LoadMoreItemsAsync(uint count)
        {
            if (_busy)
            {
                throw new InvalidOperationException("Only one operation in flight at a time");
            }

            _busy = true;

            count = 20;

            return AsyncInfo.Run((c) => LoadMoreItemsAsync(c, count));
        }

        /// <summary>
        /// 获取支持增量加载实现的 Sentinel 值。
        /// </summary>
        /// <returns>
        /// 如果附加卸载项保留在视图中，则为 true；否则为 false。
        /// </returns>
        public bool HasMoreItems { get; private set; } = true;

        protected async Task<LoadMoreItemsResult> LoadMoreItemsAsync(CancellationToken c, uint count)
        {
            try
            {
                if (this.OnLoadMoreStarted != null)
                {
                    this.OnLoadMoreStarted(count);
                }

                // 我们忽略了CancellationToken，因为我们暂时不需要取消，需要的可以加上
                
                var result = await this._dataFetchDelegate(_start, (int)count);

                _start += (int)count;
                var items = result.Item1;

                if (items != null)
                {
                    foreach (var item in items)
                    {
                        this.Add(item);
                    }
                }

                // 是否还有更多
                this.HasMoreItems = result.Item2;

                // 加载完成事件
                if (this.OnLoadMoreCompleted != null)
                {
                    this.OnLoadMoreCompleted(items == null ? 0 : items.Count());
                }

                return new LoadMoreItemsResult { Count = items == null ? 0 : (uint)items.Count() };
            }
            finally
            {
                _busy = false;
            }
        }


        public delegate void LoadMoreStarted(uint count);
        public delegate void LoadMoreCompleted(int count);

        public event LoadMoreStarted OnLoadMoreStarted;
        public event LoadMoreCompleted OnLoadMoreCompleted;

        private bool _busy = false;

        public async Task Refresh()
        {
            //reset
            Clear();
        }

        public new void Clear()
        {
            _start = 0;
            base.Clear();
            HasMoreItems = true;
        }
    }
}
